<?php
/**
 * Created by PhpStorm.
  * User: longli
 * Date: 17/7/27
 * Time: 上午10:48
 * @link http://www.lmterp.cn
 */

namespace app\common\library;

class FileCsv
{
  /**
   * 文件
   * @var string
   */
  protected $file;

  /**
   * 文件编码
   * @var string
   */
  protected $encode;

  /**
   * 错误信息
   * @var array
   */
  protected $error = [];

  /**
   * 读取的数据
   * @var array
   */
  protected $data = [];

  /**
   * 控制跳过多少行
   * @var int
   */
  protected $index = 1;

  /**
   * 每次读取多少行
   * @var int
   */
  protected $readLine = 100;

  /**
   * FileCsv constructor.
   * @param string $file 文件路径
   * @throws Exception
   */
  public function __construct($file = '')
  {
    ini_set('memory_limit','-1');
    set_time_limit(0);
    $this->file = $file;
    if(!file_exists($file))
    {
      throw new Exception("文件不存在");
    }
    $this->encode = $this->getEncode();
  }

  /**
   * 递归去除左右空白字符
   * @param array|string $data 要处理的数组或字符串
   * @return array|string
   */
  public function trim($data)
  {
    return is_array($data)
      ? array_map([$this, __FUNCTION__], $data)
      : trim($data);
  }

  /**
   * 读取csv文件
   * @param array $keys 设置下标，如果不设置则使用指定的行为下标
   * @return array|bool
   * @author longli
   */
  public function readFile(array $keys = [])
  {
    if(!is_file($this->file))
      $this->error[] = '文件不存在';
    if(!empty($this->error))
      return false;

    $index = $this->getIndex();
    $ii = 0;
    $data =  [];
    $fp = fopen($this->file, "r");
    while(($line = fgetcsv($fp)) !== false)
    {
      $line = Tools::toUTF8(Tools::trim($line), $this->encode);
      if($ii <= $index)
      {
        if(empty($keys) && $ii == $index)
        {
          $keys = $line;
        }
        $ii++;
        continue;
      }
      $data[] = array_combine($keys, $line);
    }
    fclose($fp);
    return $this->data = $data;
  }

  /**
   * 检测文件
   * @return bool
   */
  public function check()
  {
    $suffix = mb_strtolower(substr(strrchr($this->file, '.'), 1 ));
    $finfo = finfo_open(FILEINFO_MIME_TYPE);
    $info = finfo_file($finfo, $this->file);
    finfo_close($finfo);
    if(in_array($suffix, ['csv', 'tmp']) && $info == 'text/plain')
    {
      return true;
    }
    else
    {
      $this->error[] = '文件格式不对，请上传csv文件格式';
      return false;
    }
  }

  /**
   * 分段读取文件
   * @param array $keys 设置下标，如果不设置则使用指定的行为下标
   * @return bool
   */
  public function readSubFile(array $keys = [])
  {
    if(!is_file($this->file))
      $this->error[] = '文件不存在';

    if(!empty($this->error))
      return false;
    $gi = $ii = 0;
    $fp = fopen($this->file, "r");
    $data = $keys = [];
    $num = $index = $this->getIndex();
    $readLine = $this->getReadLine();
    $countData = count($this->getData());
    if($countData > 0)
      $num += $readLine - $countData;
    while(($line = fgetcsv($fp)) !== false)
    {
      $line = Tools::toUTF8(Tools::trim($line), $this->encode);
      if($ii <= $index)
      {
        if(empty($keys) && $ii == $index)
        {
          $keys = $line;
        }
        $ii++;
        continue;
      }
      $gi++;
      if($gi == $num)
      {
        $num++;
        $data[] = array_combine($keys, $line);
      }
      if($num > $readLine)
      {
        break;
      }
    }
    fclose($fp);
    $this->setReadLine($this->getReadLine() + count($data));
    $this->data = $data;
    return !empty($data);
  }

  /**
   * @return array
   */
  public function getError()
  {
    return $this->error;
  }

  /**
   * @return array
   */
  public function getData()
  {
    return !empty($this->getError()) ? $this->getError() : $this->data;
  }

  /**
   * @return string
   */
  public function getFile()
  {
    return $this->file;
  }

  /**
   * @param int $index
   */
  public function setIndex($index)
  {
    $this->index = $index;
  }

  /**
   * @return int
   */
  public function getIndex()
  {
    return $this->index;
  }

  /**
   * @return int
   */
  public function getReadLine()
  {
    return $this->readLine;
  }

  /**
   * @param int $readLine
   */
  public function setReadLine($readLine)
  {
    $this->readLine = $readLine;
  }

  /**
   * 获取当前csv文件编码
   * @return string
   */
  public function getEncode()
  {
    if(!empty($this->encode))
      return $this->encode;
    $fp = fopen($this->file, 'r');
    $data = fgetcsv($fp);
    fclose($fp);
    return $this->encode = mb_detect_encoding(current($data), ['ASCII', 'UTF-8', 'GB2312', 'GBK', 'EUC-CN', 'BIG5']);
  }
}